#!/bin/bash

# Repository Update Script
# Function: Check remote updates, stash local changes, pull updates, and restore stashed changes

# Set UTF-8 encoding support
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

# ============================================
# Configuration and Global Variables
# ============================================

# Set working directory
if [ -z "$AWS" ]; then
    if [ -n "$HOME" ]; then
        export AWS="$HOME/workspace"
    else
        export AWS="/Users/$(whoami)/workspace"
    fi
fi

# Repository path
REPO_PATH="$AWS/demo"

# ============================================
# Utility Functions
# ============================================

# Log function
log() {
    local level=$1
    local message=$2
    local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    local level_str
    
    case $level in
        0) level_str="ERROR" ;;
        1) level_str="WARN"  ;;
        2) level_str="INFO"  ;;
        3) level_str="DEBUG" ;;
        *) level_str="UNKNOWN" ;;
    esac
    
    if [ $level -le 2 ]; then
        echo "[$timestamp] [$level_str] $message"
    fi
}

# Check if command exists
check_command() {
    local cmd=$1
    local desc=$2
    
    if ! command -v "$cmd" > /dev/null 2>&1; then
        log 0 "Error: Command $cmd ($desc) not found, please install it first."
        return 1
    fi
    return 0
}

# Check if directory is a Git repository
check_git_repo() {
    local repo_path=$1
    
    if [ ! -d "$repo_path" ]; then
        log 0 "Error: Directory does not exist: $repo_path"
        return 1
    fi
    
    if [ ! -d "$repo_path/.git" ]; then
        log 0 "Error: Not a Git repository (missing .git directory): $repo_path"
        return 1
    fi
    
    return 0
}

# Show help information
show_help() {
    echo "Repository Update Tool"
    echo "Usage: $0 [options]"
    echo ""
    echo "Function: Check remote updates, stash local changes, pull updates, and restore stashed changes"
    echo ""
    echo "Options:"
    echo "  --help, -h        Show this help information"
    echo "  --repo <path>     Specify repository path (default: $REPO_PATH)"
    echo ""
}

# ============================================
# Main Functions
# ============================================

# Check if there are unpushed commits
check_unpushed_commits() {
    local repo_path=$1
    local unpushed_count=0
    
    cd "$repo_path" || return 1
    
    # Get count of unpushed commits
    if command -v git &>/dev/null; then
        unpushed_count=$(git log --oneline origin/$(git rev-parse --abbrev-ref HEAD)..HEAD 2>/dev/null | wc -l | tr -d ' ')
    fi
    
    echo "$unpushed_count"
}

# Soft reset unpushed commits (keep changes staged)
soft_reset_unpushed() {
    local repo_path=$1
    local unpushed_count=$2
    
    cd "$repo_path" || return 1
    
    if [ "$unpushed_count" -gt 0 ]; then
        log 2 "Soft resetting $unpushed_count unpushed commits"
        git reset --soft HEAD~$unpushed_count
        log 2 "Soft reset completed"
    else
        log 2 "No unpushed commits to reset"
    fi
}

# Stash local changes
stash_changes() {
    local repo_path=$1
    
    cd "$repo_path" || return 1
    
    # Check if there are changes to stash
    if ! git diff-index --quiet HEAD -- || ! git diff-files --quiet; then
        log 2 "Stashing local changes"
        git stash push -m "Auto-stashed by repo_update.sh $(date)"
        log 2 "Changes stashed successfully"
        return 0
    else
        log 2 "No local changes to stash"
        return 1
    fi
}

# Pull updates from remote
pull_updates() {
    local repo_path=$1
    
    cd "$repo_path" || return 1
    
    log 2 "Fetching latest changes from remote"
    git fetch origin
    
    log 2 "Checking for updates"
    local local_commit=$(git rev-parse HEAD)
    local remote_commit=$(git rev-parse origin/$(git rev-parse --abbrev-ref HEAD))
    
    if [ "$local_commit" != "$remote_commit" ]; then
        log 2 "Updates found, pulling changes"
        git pull --rebase origin $(git rev-parse --abbrev-ref HEAD)
        local pull_result=$?
        
        if [ $pull_result -eq 0 ]; then
            log 2 "Updates pulled successfully"
        else
            log 0 "Failed to pull updates"
            return $pull_result
        fi
    else
        log 2 "Already up to date"
    fi
    
    return 0
}

# Apply stashed changes
apply_stashed_changes() {
    local repo_path=$1
    
    cd "$repo_path" || return 1
    
    # Check if there are stashed changes
    if git stash list | grep -q "Auto-stashed by repo_update.sh"; then
        log 2 "Applying stashed changes"
        git stash apply
        local apply_result=$?
        
        if [ $apply_result -eq 0 ]; then
            log 2 "Stashed changes applied successfully"
        else
            log 1 "Conflicts occurred while applying stashed changes. Please resolve manually."
            return $apply_result
        fi
    else
        log 2 "No stashed changes to apply"
    fi
    
    return 0
}

# Update repository
update_repo() {
    local repo_path=$1
    
    log 2 "Updating repository: $repo_path"
    
    # Check if it's a valid Git repository
    check_git_repo "$repo_path" || return 1
    
    # Change to repository directory
    cd "$repo_path" || return 1
    
    # Check Git availability
    check_command git "Git version control tool" || return 1
    
    # Check current branch
    local current_branch=$(git rev-parse --abbrev-ref HEAD)
    log 2 "Current branch: $current_branch"
    
    # Check for unpushed commits
    local unpushed_count=$(check_unpushed_commits "$repo_path")
    log 2 "Unpushed commits: $unpushed_count"
    
    # Soft reset unpushed commits if any
    if [ "$unpushed_count" -gt 0 ]; then
        soft_reset_unpushed "$repo_path" "$unpushed_count"
    fi
    
    # Stash local changes
    local has_stashed_changes=false
    if stash_changes "$repo_path"; then
        has_stashed_changes=true
    fi
    
    # Pull updates
    pull_updates "$repo_path"
    local pull_result=$?
    
    # Apply stashed changes if we had any
    if [ "$has_stashed_changes" = true ]; then
        apply_stashed_changes "$repo_path"
    fi
    
    # Drop the stash if it was created by this script
    if [ "$has_stashed_changes" = true ] && git stash list | grep -q "Auto-stashed by repo_update.sh"; then
        git stash drop
        log 2 "Dropped auto-created stash"
    fi
    
    return $pull_result
}

# ============================================
# Main Program
# ============================================

# Parse command line arguments
while [ $# -gt 0 ]; do
    case $1 in
        --help|-h)
            show_help
            exit 0
            ;;
        --repo)
            if [ -n "$2" ]; then
                REPO_PATH="$2"
                shift 2
            else
                log 0 "Error: --repo option requires a path argument"
                show_help
                exit 1
            fi
            ;;
        *)
            log 0 "Unknown parameter: $1"
            show_help
            exit 1
            ;;
    esac
done

# Execute update
update_repo "$REPO_PATH"
exit $?